from __future__ import absolute_import
from celery import shared_task

# from iClouds.celery import app
# from celery.utils.log import get_task_logger
# from celery.schedules import crontab

from django.conf import settings
from django.utils import timezone
from django_redis import get_redis_connection
from iClouds.SDKqwin import call_with_callback, call_with_messages
from django_celery_beat.models import PeriodicTask, PeriodicTasks
import uuid
import logging
import time
import os
import json
import math
import requests
import shutil
from base64 import b64decode, b64encode
from mysqldb.models import (
    AllinpayWxchatList,
    AllinpayRobotModels,
    AllinpayRobotList,
    AllinpayRobotBase,
    AllinpayRobotConfig,
    AllinpayRobotConfigShare,
    AllinpayRobotQiniu,
    AllinpayRobotReqsn,
    AllinpayRobotReqsnRefund,
    AllinpayRobotAccount,
    AllinpayRobotQiniuLog,
    AllinpayRobotListmyShare,
    AllinpayWxchatSpread,
)
from mysqldb.tasks import (
    WeAppsOpenidformSend,
    balance_from_userid,
    balance_from_userai,
    EncryptedData,
)
from iClouds.wechatcfg import wxChatRequest
from iClouds.SDKweApp import wxAppsRequest
from iClouds.SDKwePay import wxPaysRequest
from iClouds.SDKsync import syncRequest
from iClouds.SDKopencv import myOpencv
from iClouds.SDKqiniu import qiMainThead
from iClouds.SDKsovits import soVitsMainPage
from iClouds.apiheader import has_chocode, is_valid_url
from .Serializers import AllinpayRobotQiniuLogSerializer

logger = logging.getLogger(__name__)


@shared_task
def has_tasks_log(*args, **kwargs):
    """加载任务对象"""
    try:
        r = AllinpayRobotQiniuLog.objects.get(id=kwargs.get("idx"))
    except BaseException as err:
        return None
    else:
        return r


@shared_task
def audio_Controller(*args, **kwargs):
    """声音合成控制器"""

    rds = get_redis_connection("sysconf")
    # 检测数据
    if not rds.llen("audio"):
        return {"rescode": 404, "resmsg": "null"}
    # 缓存锁
    lock = rds.setnx("do_audio", "lock")
    if not lock:
        return {"rescode": 400, "resmsg": "ONLOCK"}
    # logger.info(f"[声音合成控制器] {type(lock)} {lock}")
    # 加载任务
    idx = rds.lpop("audio")
    if not idx:
        rds.delete("do_audio")
        return {"rescode": 404, "resmsg": "null"}
    # 加载任务
    task = has_tasks_log(**{"idx": idx})
    if not task:
        rds.delete("do_audio")
        return {"rescode": 400, "resmsg": "加载任务失败"}

    logger.info(f"[声音合成控制器] 开始 {idx}")
    # 生成声音
    SDK = soVitsMainPage()
    res = SDK.tts(idx)
    logger.info(f'[声音合成控制器] 返回 {idx} {res.get("rescode")} {res.get("resmsg")}')
    # 返回结果
    if res.get("rescode") == 200 and task.mode in ["Audio", "Voice"]:
        task.audio = res.get("resmsg")
        task.status = 1
        task.description = "完成"
        task.lasttime = timezone.now()
        task.save()
        # 设置结果
        rds = get_redis_connection("sysconf")
        rds.set(task.guid, task.audio)
        rds.expire(task.guid, 180)
    if res.get("rescode") == 200 and task.mode in [
        "Video",
        "Mpeg",
        "Lipsync",
        "Opencv",
    ]:
        task.audio = res.get("resmsg")
        task.description = "等待"
        task.save()
    if task.mode in ["Video", "Mpeg"]:
        rds.rpush("video", task.id)
    if task.mode == "Lipsync":
        rds.rpush("lipsync", task.id)
    if task.mode == "Opencv":
        rds.rpush("opencv", task.id)
    if task.mode == "Voice":
        weChatModelMessages.delay(**{"task": task.id})
    logger.info(f"[声音合成控制器] 结束 {idx}")
    rds.delete("do_audio")
    return {"rescode": 200, "resmsg": "SUCCESS"}


@shared_task
def video_Controller(*args, **kwargs):
    """视频合成控制器"""
    rds = get_redis_connection("sysconf")
    # 检测数据
    if not rds.llen("video"):
        return {"rescode": 404, "resmsg": "null"}
    # 缓存锁
    lock = rds.setnx("do_video", "lock")
    if not lock:
        return {"rescode": 400, "resmsg": "ONLOCK"}
    # logger.info(f"[视频合成控制器] 开始 {type(lock)} {lock}")

    # logger.info(f"[视频合成控制器] 结束")
    rds.delete("do_video")
    return {"rescode": 200, "resmsg": "SUCCESS"}


@shared_task
def lipsync_Controller(*args, **kwargs):
    """唇动合成控制器"""
    rds = get_redis_connection("sysconf")
    # 检测数据
    if not rds.llen("lipsync"):
        return {"rescode": 404, "resmsg": "null"}
    # 缓存锁
    lock = rds.setnx("do_lipsync", "lock")
    if not lock:
        return {"rescode": 400, "resmsg": "ONLOCK"}
    # logger.info(f"[唇动合成控制器] {type(lock)} {lock}")

    # 加载任务
    idx = rds.lpop("lipsync")
    if not idx:
        rds.delete("do_lipsync")
        return {"rescode": 404, "resmsg": "null"}
    # 加载任务
    task = has_tasks_log(**{"idx": idx})
    if not task:
        rds.delete("do_lipsync")
        return {"rescode": 400, "resmsg": "加载任务失败"}

    logger.info(f"[唇动合成控制器] 开始 {idx}")
    # 开始任务
    SDK = syncRequest()
    res = SDK.postLipsync(
        **{
            "audio": task.audio,
            "video": task.video,
        }
    )
    logger.info(f"[AI唇动合成] 返回 {idx} {res}")
    #  {'id': 'ca98f2e1-b26b-4762-85b5-34192637ecee', 'createdAt': '2024-08-28T08:47:15.525188+00:00', 'status': 'PENDING', 'videoUrl': None, 'originalVideoUrl': 'https://oss.3vppt.com/ppt_media/FnTk_d5I0MDY-ydymibvVYIStbmU&video.mp4', 'originalAudioUrl': 'https://oss.3vppt.com/ppt_media/FuqlU-NZqcAvz56L7ojtCVcus82G&output.wav', 'synergize': True, 'creditsDeducted': None, 'webhookUrl': 'https://lease.3vppt.com/rebot/dosync/', 'errorMessage': None}
    if res.get("id"):
        task.description = res.get("id")
        task.save()
    # {'statusCode': 400, 'message': 'Video file is not accessible'}
    if res.get("statusCode"):
        task.description = res.get("message")
        task.save()
    logger.info(f"[唇动合成控制器] 结束 {idx}")
    rds.delete("do_lipsync")
    return {"rescode": 200, "resmsg": "SUCCESS"}


@shared_task
def opencv_Controller(*args, **kwargs):
    """单图合成控制器"""
    rds = get_redis_connection("sysconf")
    # 检测数据
    if not rds.llen("opencv"):
        return {"rescode": 404, "resmsg": "null"}
    # 缓存锁
    lock = rds.setnx("do_opencv", "lock")
    if not lock:
        return {"rescode": 400, "resmsg": "ONLOCK"}
    # logger.info(f"[单图合成控制器] {type(lock)} {lock}")

    # 加载任务
    idx = rds.lpop("opencv")
    if not idx:
        rds.delete("do_opencv")
        return {"rescode": 404, "resmsg": "null"}
    # 加载任务
    task = has_tasks_log(**{"idx": idx})
    if not task:
        rds.delete("do_opencv")
        return {"rescode": 400, "resmsg": "加载任务失败"}

    logger.info(f"[单图合成控制器] 开始 {idx}")
    # 开始任务
    SDK = myOpencv()
    res = SDK.doWorking(**{"audio": task.audio, "image": task.image})
    logger.info(f"[AI单图合成] 返回 {idx} {res}")
    # 转储文件
    outfile = (
        settings.BASE_DIR.parent
        / f'statics/video/{time.strftime("%Y-%m-%d", time.localtime())}/{has_chocode(16,1).upper()}'
    )
    if not os.path.exists(outfile):
        os.makedirs(outfile)
    outfile = os.path.join(outfile, "video.mp4")
    shutil.move(res, outfile)
    # 保存任务
    task.video = "https://lease.3vppt.com/static" + outfile.split("statics")[1]
    task.status = 1
    task.lasttime = timezone.now()
    task.description = "完成"
    task.save()

    if task.mode == "opencv":
        # 设置结果
        rds = get_redis_connection("sysconf")
        rds.set(task.guid, task.video)
        rds.expire(task.guid, 180)
        weChatModelMessages.delay(**{"task": task.id})
    logger.info(f"[单图合成控制器] 结束 {idx}")
    rds.delete("do_opencv")
    return {"rescode": 200, "resmsg": "SUCCESS"}


@shared_task
def task_Consumption(*args, **kwargs):
    """任务消费管理器"""

    def has_model(uid):
        """加载模型"""
        try:
            r = AllinpayRobotConfig.objects.get(id=uid)
        except BaseException as err:
            return None
        else:
            return r

    try:  # 加载任务
        task = AllinpayRobotQiniuLog.objects.get(id=kwargs.get("task_id"))
    except BaseException as err:
        logger.warn(f"[任务消费管理器] 加载任务失败 {err}")
        raise Exception("加载任务失败")
    else:
        if task.status:
            raise Exception("已经完成的任务")
        if task.sell:
            return True

    # 参与分成项目
    modes = ["Audio", "Voice"]
    if task.mode in modes:
        model = has_model(task.model)
        if not model:
            logger.warn(f"[任务消费管理器] 加载模型失败")
            raise Exception("加载模型失败")
        if not task.answer == model.answer:
            try:
                share = AllinpayRobotConfigShare.objects.get(id=model.id)
            except BaseException as err:
                logger.warn(f"[任务消费管理器] 加载共享模型失败 {err}")
                raise Exception("加载共享模型失败")
            else:
                added = share.audio
        else:
            added = 0
    else:
        added = 0

    sell = balance_from_userai(task.mode)
    guota = sell[0] + added
    args = balance_from_userid(task.answer)
    if args[0] < guota:
        logger.warn(f"[任务消费管理器] 账户余额不足 {err}")
        raise Exception("账户余额不足")
    pay = User_account_deduction(
        **{
            "reqsn": task.reqsn,
            "description": sell[1],
            "amoney": guota,
            "atotal": 0,
            "userid": task.answer,
            "dbid": settings.ROBOT_MONEY_DEFAULT,
            "current": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
        }
    )
    if not pay == "success":
        logger.warn(f"[任务消费管理器] 扣费失败 {pay}")
        raise Exception("扣费失败")
    # 创建入账
    if added > 0:
        licre = 0 - math.ceil(added * settings.RPBOT_MONEY_SHARE / 100)
        repay = User_account_deduction(
            **{
                "reqsn": f"{task.reqsn}A",
                "description": sell[1] + ", 模型返点",
                "amoney": licre,
                "atotal": 0,
                "userid": model.answer,
                "dbid": settings.ROBOT_MONEY_DEFAULT,
                "current": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
            }
        )
        if not repay == "success":
            logger.warn(f"[任务消费管理器] 入账失败 {pay}")
    # 保存结果
    task.amoney = guota
    task.sell = 1
    task.save()
    return True


@shared_task
def tasks_Manager(*args, **kwargs):
    """任务调度管理器"""
    try:  # 加载任务
        task = AllinpayRobotQiniuLog.objects.get(id=kwargs.get("task_id"), sell=1, status=0)
    except BaseException as err:
        logger.warn(f"[任务调度管理器] 加载任务失败 {err}")

    # 执行任务
    rds = get_redis_connection("sysconf")
    if task.matter and not task.chat:
        res = do_ChatForText(**{"user": task.mate, "share": task.matr, "chat": task.matter})
        task.chat = res["resmsg"]
        task.save()

    if task.mode == "content":
        weChatModelMessages.delay(**{"task": task.id})

    if task.mode in ["Text", "content"]:
        task.description = "完成"
        task.lasttime = timezone.now()
        task.status = 1
        task.save()
        # 设置结果
        rds = get_redis_connection("sysconf")
        rds.set(
            task.guid,
            res["resmsg"],
        )
        rds.expire(task.guid, 180)
        return {"rescode": 200, "resmsg": res["resmsg"]}

    if task.mode in ["Audio", "Voice"]:
        rds.rpush(
            "audio",
            task.id,
        )
        count = rds.llen("audio")
        # audio_Controller.delay()
    if task.mode in ["Video", "Mpeg"]:
        act = "video" if task.audio else "audio"
        rds.rpush(act, task.id)
        count = rds.llen(act)
        # video_Controller.delay()
    if task.mode in ["Lipsync"]:
        act = "lipsync" if task.audio else "audio"
        rds.rpush(act, task.id)
        count = rds.llen(act)
        # lipsync_Controller.delay()
    if task.mode in ["Opencv"]:
        act = "opencv" if task.audio else "audio"
        rds.rpush(act, task.id)
        count = rds.llen(act)
        # opencv_Controller.delay()
    return {"rescode": 200, "resmsg": "SUCCESS"}


@shared_task
def AI_Auto_Tasks_Event(*args, **kwargs):  # 应用中
    """
    定时任务
    kwargs = {'event': 1, 'usert': 1, 'answer': 1, 'share':0}
    """

    def has_mode(mid):
        """查询订阅模板 返回: 模板对象"""
        try:
            r = AllinpayRobotModels.objects.get(id=mid)
        except BaseException as err:
            return None
        else:
            return r

    def has_share(uid):
        """返回共享好友"""
        try:
            r = AllinpayRobotListmyShare.objects.get(id=uid)
        except BaseException as err:
            return None
        else:
            return r

    def has_virtai(uid):
        """查询虚拟身份 返回: 好友对象, 声音模型对象"""
        try:
            r = AllinpayRobotList.objects.get(id=uid)
        except BaseException as err:
            return None
        else:
            return r

    def has_model(uid):
        """查询模型"""
        try:
            r = AllinpayRobotConfig.objects.get(id=uid, status=1)
        except BaseException as err:
            return None
        else:
            return r

    def has_openid(uid):
        """查询openid"""
        try:
            r = AllinpayRobotList.objects.get(id=uid)
            c = AllinpayWxchatList.objects.get(userid=r.parent)
        except BaseException as err:
            return None
        else:
            return c.openid

    def wait_respion(guid, timer=1200):
        """等待结果 返回:
        {'id':57,'code': 200, 'data': 'ppt_media/Fn8_a23aS5F3qjfiHbIMJFzpOdKO&audio.wav'}
        """
        t, rds = 0, get_redis_connection("sysconf")
        while t < timer:
            if rds.exists(guid):
                return json.loads(rds.get(guid))
            time.sleep(1)
            t += 1
        return None

    """开始"""
    # 创建任务ID
    guid, reqsn = (
        str(uuid.uuid1()),
        f'AT{time.strftime("%Y%m%d%H%M%S", time.localtime())}{has_chocode(6)}',
    )
    # 用户身份
    if not kwargs.get("share"):
        user = has_virtai(kwargs.get("usert"))
    else:
        user = has_share(kwargs.get("usert"))
    if not user:
        logger.warn(f"[自动任务] 加载人物失败")
        return {"rescode": 400, "resmsg": "加载人物失败"}
    # 加载模型
    model = has_model(user.isbot)
    if not model:
        logger.warn(f"[自动任务] 加载模型失败")
        return {"rescode": 400, "resmsg": "加载模型失败"}
    # 加载模板
    print("模板ID", kwargs["event"])
    mode = has_mode(kwargs["event"])
    print("模板:", mode)
    logger.info(f"[自动任务] {kwargs}")

    # 创建任务
    job = AllinpayRobotQiniuLog(
        **{
            "reqsn": reqsn,
            "guid": guid,
            "mark": mode.mark,
            "mode": mode.mode,
            "model": model.id,
            "mate": user.id,
            "matr": kwargs.get("share"),
            "answer": kwargs["answer"],
            "status": 0,
            "current": timezone.now(),
            "description": "订阅任务",
            "language": "Chinese",
            "matter": mode.content,
            "image": mode.image,
            "audio": mode.audio,
            "video": mode.video,
        }
    )
    job.save()
    if mode.mode == "Lipsync":
        job.video = kwargs.get("video")
        job.save()
    try:  # 扣费
        task_Consumption(**{"task_id": job.id})
    except BaseException as err:
        logger.warn(f"[自动任务] 扣款失败 {err}")
        return {"rescode": 400, "resmsg": "定时任务失败"}
    # 任务调度
    res = tasks_Manager.delay(**{"task_id": job.id})
    return {"rescode": 200, "resmsg": "定时任务完成"}


# ==================================================================
# 分割线
# ==================================================================
# @shared_task
# def clone_Share_friend(*args, **kwargs):
#     """克隆共享好友"""
#     share = kwargs.get("share")
#     try:
#         r = AllinpayRobotListmyShare.objects.get(id=share, status=1)
#         s = AllinpayRobotList.objects.get(id=r.vid, share__gt=0)
#     except BaseException as err:
#         logger.warn(f"[克隆好友] 查询许可失败 {err}")
#         return {"rescode": 400, "resmsg": "err"}
#     return {"rescode": 200, "resmsg": "seccuss"}


# ==================================================================
# 分割线
# ==================================================================
@shared_task
def do_Test(*args, **kwargs):
    """测试"""
    logger.info(f"[测试任务] {kwargs}")
    return {"rescode": 200, "resmsg": "HelloWorld"}


@shared_task
def has_models_aiid(user):
    """根据虚拟好友ID查询ai模型ID"""
    try:
        r = AllinpayRobotList.objects.get(id=user)
    except BaseException as err:
        return None
    else:
        return r.isbot


@shared_task
def do_AudioForAudio(*args, **kwargs):
    """语音解析
    kwargs = {
        "user": 1, "audio":"path",
    }
    """
    audio = []
    audio.append(kwargs.get("audio"))
    res = eval(call_with_callback(audio))
    # logger.info(f"[语音解析] 返回结果:{type(res)} {res}")
    try:
        url = res["results"][0]["transcription_url"]
        r = requests.get(url)
        text = r.json()
        text = text["transcripts"][0]["text"]
    except BaseException as err:
        return {"rescode": 400, "resmsg": res.get("task_status", f"{err}")}
    else:
        return {"rescode": 200, "resmsg": text}


@shared_task
def do_ChatForText(*args, **kwargs):  # 需要调用
    """聊天模式
    kwargs = {
        "user":1, "chat": [{"role": "user", "content": "如何做西红柿炒鸡蛋？"}]
    }
    """
    user, msg = kwargs.get("user"), [{"role": "user", "content": kwargs.get("chat")}]
    try:
        bname, nname, link = "陌生人", "陌生人", "陌生人"
        if kwargs.get("share"):
            share = AllinpayRobotListmyShare.objects.get(id=user)
            answer = AllinpayRobotList.objects.get(id=share.vid)
            bname, nname, link = answer.basename, share.nicename, share.linkforme
        else:
            answer = AllinpayRobotList.objects.get(id=user)
            bname, nname, link = answer.basename, answer.nicename, answer.linkforme
        audio = AllinpayRobotConfig.objects.get(id=answer.isbot)
        text = msg[-1]["content"]
        msg[-1]["content"] = f"你是{bname},昵称{nname},身份是我的{link}。请和我聊聊：{text}"
    except BaseException as err:
        return {"rescode": 200, "cast": msg, "resmsg": err}

    res = call_with_messages(msg)
    if res:
        answer = res["choices"][-1]["message"]
        bot_message = answer["content"]
    else:
        bot_message = "抱歉，我无法回答这个问题"
    return {"rescode": 200, "cast": kwargs.get("cast"), "resmsg": bot_message}


@shared_task
def do_ChatForAudio(*args, **kwargs):
    """音频合成
    kwargs = {
        "user":1, "chat": "你好，有什么需要效劳的吗？"}
    """

    def has_virtai(uid):
        """查询虚拟身份"""
        try:
            r = AllinpayRobotList.objects.get(id=uid)
            c = AllinpayRobotConfig.objects.get(id=r.isbot, status=1)
        except BaseException as err:
            return []
        else:
            return r, c

    # 格式化数据
    res = dict(kwargs).copy()
    event = has_virtai(res["user"])

    # 判断余额
    args = balance_from_userid(res["answer"])
    if args[0] < settings.RPBOT_MONEY_AUDIO:
        return {"rescode": 400, "resmag": "账户余额不足"}

    # 创建扣费
    reqsn = f'VP{time.strftime("%Y%m%d%H%M%S", time.localtime())}{has_chocode(6)}'
    sell = balance_from_userai("Audio")
    pay = User_account_deduction(
        **{
            "reqsn": reqsn,
            "description": sell[1],
            "amoney": sell[0],
            "atotal": 0,
            "userid": res["answer"],
            "dbid": settings.ROBOT_MONEY_DEFAULT,
            "current": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
        }
    )
    if not pay == "success":
        return {"rescode": 400, "resmag": "支付失败"}

    # 创建任务
    # print(serializer.data)
    szer = AllinpayRobotQiniuLogSerializer(
        data={"chat": res["chat"], "guid": res["guid"], "language": "Chinese"}
    )
    szer.is_valid(raise_exception=True)
    szer.save(
        answer=res["answer"],
        mode="Audio",
        reqsn=reqsn,
        amoney=sell[0],
        model=event[1].id,
        mate=event[0].id,
    )

    # 云任务
    r = MakeSoundTasks(**{"task_id": szer.data["id"]})
    # 任务缓存
    # rds = get_redis_connection("sysconf")
    # rds.rpush(
    #     "audio",
    #     szer.data["id"],
    # )
    # count = rds.llen("audio")

    return {
        "rescode": 200,
        "resmsg": kwargs.get("guid"),
        "content": kwargs.get("chat"),
    }


@shared_task
def do_ChatForVideo(*args, **kwargs):
    """视频合成  停用
    kwargs = {
        "user":1,
        "audio": "http://oss.3vppt.com/ppt_media/FvNPQA7XADbuhtZcxbtDvZAY-eHQ&audio.wav",
        "image":"http://192.168.31.211:8000/static/models/models/0000.png",
        "lange":10}
    """

    def has_virtai(uid):
        """查询虚拟身份"""
        try:
            r = AllinpayRobotList.objects.get(id=uid)
            c = AllinpayRobotConfig.objects.get(id=r.isbot, status=1)
        except BaseException as err:
            return []
        else:
            return r, c

    res = dict(kwargs).copy()

    # 强制改变近照
    event = has_virtai(res["user"])
    # res["image"] = event[1].image
    # res["user"] = event[0].parent  # has_models_aiid(res["answer"])

    # 判断余额
    args = balance_from_userid(res["answer"])
    if args[0] < settings.RPBOT_MONEY_VIDEO:
        return {"rescode": 400, "resmag": "账户余额不足"}

    # 创建扣费
    reqsn = f'VP{time.strftime("%Y%m%d%H%M%S", time.localtime())}{has_chocode(6)}'
    sell = balance_from_userai("Video")
    pay = User_account_deduction(
        **{
            "reqsn": reqsn,
            "description": sell[1],
            "amoney": sell[0],
            "atotal": 0,
            "userid": res["answer"],
            "dbid": settings.ROBOT_MONEY_DEFAULT,
            "current": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
        }
    )
    if not pay == "success":
        return {"rescode": 400, "resmag": "支付失败"}

    # 创建任务
    # print(serializer.data)
    szer = AllinpayRobotQiniuLogSerializer(
        data={"image": event[1].image, "audio": res["audio"], "guid": res["guid"]}
    )
    szer.is_valid(raise_exception=True)
    szer.save(
        answer=res["answer"],
        mode="Video",
        reqsn=reqsn,
        amoney=sell[0],
        mate=event[0].id,
    )
    # 云任务
    r = MakeSoundTasks(**{"task_id": szer.data["id"]})
    # # 任务缓存
    # rds = get_redis_connection("sysconf")
    # rds.rpush(
    #     "video",
    #     szer.data["id"],
    # )
    # count = rds.llen("video")
    return {"rescode": 200, "resmsg": kwargs.get("guid"), "count": 0}


@shared_task
def do_TextForVideo(*args, **kwargs):
    """
    文本合成视频 参数:{
        'user': 5, 'language': 'Chinese',
        'chat': '你好，有什么可以效劳的吗？',
        'image': url, 'guid': guid, 'mode': 'Video', 'answer': 1
        }
    """

    return {"rescode": 200, "resmsg": ""}


@shared_task
def weChatModelMessages(*args, **kwargs):
    """订阅通知 微信模板消息 请求参数:{"task": r.id}"""

    def changeName(types):
        """交换名称"""
        if types in ["Text", "content"]:
            return "文本订阅"
        elif types in ["Audio", "Voice"]:
            return "音频订阅"
        elif types in ["Video", "Mpeg", "Lipsync"]:
            return "视频订阅"
        else:
            return "其他"

    def changeStatus(status):
        """交换状态"""
        if status:
            return "已完成"
        else:
            return "未完成"

    # 模板消息
    logger.info(f'[模板消息] 模板消息检测数据 {kwargs["task"]}')
    return {"rescode": 400, "resmsg": "关闭模板消息"}

    try:
        task = AllinpayRobotQiniuLog.objects.get(id=kwargs["task"])
        user = AllinpayWxchatList.objects.get(userid=task.answer)
    except BaseException as err:
        logger.warn(f"[模板消息] 查询任务或微信失败 {err}")
        return {"rescode": 400, "resmsg": "fait"}
    if not user.openid:
        logger.warn(f"[模板消息] 查询用户OPENID失败")
        return {"rescode": 400, "resmsg": "fait"}

    logger.info(f"[模板消息] 模板消息加载数据 {user.openid}")

    # 模板消息-订阅
    wx = wxChatRequest()
    r = wx.Template_ServiceAlert(
        user.openid,
        [
            task.reqsn,
            changeName(task.mode),
            changeStatus(task.status),
            timezone.now().strftime("%d-%m-%y %H:%M:%S"),
        ],
        None,
        {"appid": "wxd2ba909c0fdb075c", "dictid": task.mate, "share": task.matr},
    )
    logger.info(f"[模板消息] 模板消息提交完成 {r}")
    return {"rescode": 200, "resmsg": r}


@shared_task
def weChatModelMessagesTest(*args, **kwargs):
    """订阅通知 测试微信模板消息 请求参数:{"task": r.id}"""

    def changeName(mode):
        """交换名称"""
        if mode in ["content", "Voice", "Mpeg"]:
            return "模板消息"
        else:
            return "未知消息"

    def changeStatus(status):
        """交换状态"""
        if status:
            return "已完成"
        else:
            return "未完成"

    try:
        task = AllinpayRobotQiniuLog.objects.get(id=kwargs["task"])
        user = AllinpayWxchatList.objects.get(userid=task.answer)
    except BaseException as err:
        logger.warn(f"[自动任务] 查询任务或微信失败 {err}")
        return {"rescode": 400, "resmsg": "fait"}
    if not user.openid:
        logger.warn(f"[自动任务] 查询用户OPENID失败")
        return {"rescode": 400, "resmsg": "fait"}

    # data = {
    #     "touser": user.openid,
    #     # "id":44616,
    #     # "name":"收到服务订单通知",
    #     # "menu":"旅游服务->景区服务",
    #     "template_id": "EIxbvjflqisWvK-LrPhdM06_7lJHDrdOZ1c-f9Ybbvs",
    #     # "url": "http://weixin.qq.com/download",  # 选填
    #     "miniprogram": {  # 选填
    #         "appid": "wxd2ba909c0fdb075c",
    #         "pagepath": f"pages/History/HistoryInfo?id={task.id}",
    #     },
    #     "data": {
    #         "character_string2": {
    #             "value": task.reqsn
    #         },  # 订单号 32位以内数字、字母或符号
    #         "phrase10": {"value": changeName(task.mode)},  # 产品名称 5个以内的汉字
    #         "phrase9": {"value": changeStatus(task.status)},  # 服务状态 5个以内的汉字
    #         "time15": {
    #             "value": timezone.now().strftime("%d-%m-%y %H:%M:%S")
    #         },  # 通知时间
    #     },
    #     "client_msg_id": str(has_chocode(6)),  # 选填,防止重发
    # }
    # 模板消息-订阅
    wx = wxChatRequest()
    r = wx.Template_ServiceAlert(
        user.openid,
        [
            task.reqsn,
            changeName(task.mode),
            changeStatus(task.status),
            timezone.now().strftime("%d-%m-%y %H:%M:%S"),
        ],
        None,
        {"appid": "wxd2ba909c0fdb075c", "dictid": task.id},
    )
    logger.info(f"[自动任务] 模板消息任务完成 {r}")
    return {"rescode": 200, "resmsg": r}


@shared_task
def wePaysToweAppsPrepay(*args, **kwargs):
    """
    调起小程序支付,返回 prepay_id
    请求参数:{
        'id': 7, 'appid': None, 'mchid': None,
        'reqsn': 'AI20240801120426476157',
        'description': 'VNY充值',
        'openid': 'oRhgY7fSwJFwa1_Ijdgn98Jg1a4M',
        'amount': 1, 'answer': 2, 'mark': 1,
        'creattime': '2024-08-01 12:04:25',
        'preson': 1, 'fund': 1,'money':1
    }
    """
    wx = wxPaysRequest()
    r = wx.jsapi(kwargs)
    return r


@shared_task
def wePaysToweAppsClose(*args, **kwargs):
    """关闭支付订单"""
    wx = wxPaysRequest()
    r = wx.close(kwargs)
    if not r:
        AllinpayRobotReqsn.objects.filter(reqsn=kwargs["out_trade_no"]).update(status=-1)
    return f"请求成功 {kwargs}"


@shared_task
def wePaysToweAppsRefund(*args, **kwargs):
    """退款支付订单"""
    wx = wxPaysRequest()
    r = wx.refund(kwargs)
    if r.get("status"):
        AllinpayRobotReqsn.objects.filter(reqsn=kwargs["out_trade_no"]).update(status=2)
        AllinpayRobotReqsnRefund.objects.filter(orderno=kwargs["out_trade_no"]).update(
            reqsn=kwargs["out_refund_no"], status=2, lasttime=timezone.now()
        )
    return r


@shared_task
def User_account_deduction(*args, **kwargs):
    """用户账户扣费 请求参数：{
    "reqsn": "VP20240805115347065704",
    "description": "AI模型续费",
    "amoney": 1,    "atotal": 0,
    "userid": 3,    "dbid": 1,
    "current": "2024-08-05 11:53:47"
    }"""
    # "bmoney": 0,"btotal": 0,"hmoney": "",    "htotal": ""

    # 创建扣费记录
    args = balance_from_userid(kwargs["userid"])
    if kwargs["amoney"] < 0:
        kwargs["bmoney"] = args[0] + abs(kwargs["amoney"])
    elif args[0] < kwargs["amoney"]:
        return "fail"
    else:
        kwargs["bmoney"] = args[0] - abs(kwargs["amoney"])
    kwargs["btotal"] = args[1] - kwargs["atotal"]
    kwargs["hmoney"] = EncryptedData(kwargs["bmoney"])
    kwargs["htotal"] = EncryptedData(kwargs["btotal"])
    if kwargs["amoney"] == 0:
        return "success"
    # print(args[0], kwargs["amoney"], kwargs["bmoney"])
    AllinpayRobotAccount(**kwargs).save()

    # 查用户公众号openid
    try:
        r = AllinpayWxchatList.objects.get(userid=kwargs["userid"])
        b = AllinpayRobotList.objects.get(isbot=0, parent=kwargs["userid"])
    except BaseException as err:
        return "success"
    else:
        if not r.openid:
            return "success"

    # 模板消息-消费
    WX = wxChatRequest()
    WX.Template_Consumer(
        r.openid,
        [b.id, kwargs.get("amoney"), kwargs.get("bmoney"), kwargs.get("current")],
    )

    return "success"


@shared_task
def videoFromImageForOpencv(*args, **kwargs):
    """图转视频"""
    # 判断余额
    args = balance_from_userid(kwargs["answer"])
    if args[0] < settings.RPBOT_MONEY_OPENCV:
        return {"rescode": 400, "resmag": "账户余额不足"}

    # 创建扣费
    reqsn = f'VP{time.strftime("%Y%m%d%H%M%S", time.localtime())}{has_chocode(6)}'
    sell = balance_from_userai("Opencv")
    pay = User_account_deduction(
        **{
            "reqsn": reqsn,
            "description": sell[1],
            "amoney": sell[0],
            "atotal": 0,
            "userid": kwargs["answer"],
            "dbid": settings.ROBOT_MONEY_DEFAULT,
            "current": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
        }
    )
    if not pay == "success":
        return {"rescode": 400, "resmag": "支付失败"}

    # 创建任务
    szer = AllinpayRobotQiniuLogSerializer(
        data={
            "reqsn": reqsn,
            "guid": kwargs["guid"],
            "image": kwargs["image"],
            "audio": kwargs["audio"],
            # "video": kwargs["video"],
        }
    )
    szer.is_valid(raise_exception=True)
    szer.save(answer=kwargs["answer"], mode="Opencv", reqsn=reqsn, amoney=sell[0])

    # 开始任务
    try:
        API = myOpencv()
        res = API.doWorking(**kwargs)
    except BaseException as err:
        logger.warn(f"[Opencv] {err}")
        return {"rescode": 400, "resmag": "完成"}

    logger.info(f"[Opencv] {res}")
    # return {"rescode": 200, "resmag": "完成"}
    # 上传结果
    qi = qiMainThead()
    r = qi.doUpload(res)
    logger.info(f"上传:{kwargs} https://oss.3vppt.com/{r['key']}")

    AllinpayRobotQiniuLog.objects.filter(guid=kwargs["guid"]).update(
        **{
            "video": f'https://oss.3vppt.com/{r["key"]}',
            "status": 1,
            "lasttime": timezone.now(),
            "description": "完成",
        }
    )
    # 设置结果
    rds = get_redis_connection("sysconf")
    rds.set(
        kwargs["guid"],
        str({"code": 200, "data": f'https://oss.3vppt.com/{r["key"]}', "plan": "1/1"}),
    )
    rds.expire(kwargs["guid"], 180)
    return {"rescode": 200, "resmag": "完成"}


@shared_task
def SyncDirectTrainTasks(*args, **kwargs):
    """直达任务回调"""
    try:
        task = AllinpayRobotQiniuLog.objects.get(guid=kwargs["guid"], status=0)
    except BaseException as err:
        logger.warn(f"[直达任务回调] 获取任务对象异常 {err}")
        return {"rescode": 400, "resmag": "获取任务对象异常"}

    if task.mode in ["Video", "Mpeg", "Lipsync"]:
        # Lipsync唇动任务
        SDK = syncRequest()
        res = SDK.postLipsync(
            **{
                "audio": task.audio,
                "video": task.video,
            }
        )
        if not res.get("id"):
            logger.warn(f"[Lipsync] Lipsync 请求异常 {res}")
            return {"rescode": 400, "resmag": "Lipsync 请求异常"}
        task.description = res.get("id")
        task.save()
        logger.info(f"[Lipsync] Lipsync 请求成功")
        return {"rescode": 200, "resmag": res.get("id")}
    elif task.mode == "Opencv":
        # 检查锁
        rds = get_redis_connection("sysconf")
        while rds.exists("Lock_opencv"):
            time.sleep(1)
        rds.set("Lock_opencv", "locked", nx=True)  # ex=1
        # opencv静图
        try:
            SDK = myOpencv()
            res = SDK.doWorking(**{"audio": task.audio, "image": task.image})
        except BaseException as err:
            logger.warn(f"[Opencv] 请求异常 {err}")
            return {"rescode": 400, "resmag": "Opencv 请求异常"}
        try:
            qi = qiMainThead()
            r = qi.doUpload(res)
        except BaseException as err:
            logger.warn(f"[Opencv] 上传异常 {err}")
            return {"rescode": 400, "resmag": "Opencv 请求异常"}
        else:
            logger.info(f"上传:{kwargs} https://oss.3vppt.com/{r['key']}")
        try:
            task.video = f'https://oss.3vppt.com/{r["key"]}'
            task.resource = f'https://oss.3vppt.com/{r["key"]}'
            task.status = 1
            task.lasttime = timezone.now()
            task.description = "完成"
            task.save()
        except BaseException as err:
            logger.warn(f"[Opencv] 保存结果异常 {err}")
            return {"rescode": 400, "resmag": "Opencv 保存结果异常"}
        else:
            logger.info(f"[Opencv] 保存结果完成")
        # 释放锁
        rds.delete("Lock_opencv")
        # 设置结果
        # rds = get_redis_connection("sysconf")
        rds.set(
            task.guid,
            str(
                {
                    "code": 200,
                    "data": f'https://oss.3vppt.com/{r["key"]}',
                    "plan": "1/1",
                }
            ),
        )
        rds.expire(task.guid, 180)
    else:
        logger.warn(f"[直达任务回调] 获取任务类型异常 {task.mode}")
        return {"rescode": 400, "resmag": "获取任务类型异常"}

    return {"rescode": 200, "resmag": "完成"}


# -------------------------------------------------------------------
@shared_task
def MakeWxchatAppSpread(*args, **kwargs):
    """创建小程序推广码 参数 {"id":1}"""
    try:
        res = AllinpayWxchatSpread.objects.get(id=kwargs.get("id"))
        API = wxAppsRequest()
        r = API.hasMyQrCode(res.answer)
    except BaseException as err:
        logger.warn(f"[小程序推广码] 执行任务请求失败 {err}")
        return {"rescode": 400, "resmag": "执行任务请求失败"}
    else:
        logger.info(f"[小程序推广码] 返回:{r.status_code}")
        if r.status_code == 200:
            logger.warn(f"{type(r.content)}")
            res.qrcode = b64encode(r.content).decode("utf-8")
            res.current = timezone.now()
            res.save()
        else:
            logger.warn(f"[小程序推广码] 返回:{r.content}")
        return {"rescode": 200, "resmag": "执行完成"}


# =========================================================================================
@shared_task
def MakeSoundTasks(*args, **kwargs):
    """直连音频任务"""
    # 检查锁
    rds = get_redis_connection("sysconf")
    while rds.exists("Lock_tts"):
        time.sleep(1)
    rds.set("Lock_tts", "locked", nx=True)  # ex=1
    # 当键不存在时，才执行设置操作。如果键已经存在，设置操作将不会执行。这个参数通常用于实现分布式锁，比如在多个客户端尝试获得同一个资源的锁时，只有一个客户端能够成功获取锁。
    # 开始任务
    idx = kwargs.get("task_id")
    logger.info(f"[AI声音合成] {idx} 新任务")
    try:
        task = AllinpayRobotQiniuLog.objects.get(id=idx, status=0)
    except BaseException as err:
        logger.warn(f"[AI声音合成] 失败 加载任务失败 {err}")
        return {"rescode": 400, "resmag": "任务异常"}

    # 生成声音
    SDK = soVitsMainPage()
    res = SDK.tts(idx)

    logger.info(f"[AI声音合成] {idx} {res}")
    if res.get("rescode") == 200 and task.mode in ["Audio", "Voice"]:
        task.audio = res.get("resmsg")
        task.status = 1
        task.description = "完成"
        task.lasttime = timezone.now()
        task.save()
    if res.get("rescode") == 200 and task.mode in [
        "Video",
        "Mpeg",
        "Lipsync",
        "Opencv",
    ]:
        task.audio = res.get("resmsg")
        task.description = "等待"
        task.save()
        r = SyncDirectTrainTasks(**{"guid": task.guid})
    logger.info(f"[AI声音合成] {idx} 任务完成 ")

    # 释放锁
    rds.delete("Lock_tts")
    return {"rescode": 200, "resmag": "执行完成"}


@shared_task
def videoFromSyncForLipsync(*args, **kwargs):
    """直连唇动视频任务LipSync"""

    # 检查锁
    rds = get_redis_connection("sysconf")
    w = 0
    if rds.exists("Lock_lipsync"):
        w = int(rds.get("Lock_lipsync"))
        while w == 3:
            time.sleep(1)
            w = int(rds.get("Lock_lipsync"))
    rds.set("Lock_lipsync", w + 1, nx=True)  # ex=1
    # 当键不存在时，才执行设置操作。如果键已经存在，设置操作将不会执行。这个参数通常用于实现分布式锁，比如在多个客户端尝试获得同一个资源的锁时，只有一个客户端能够成功获取锁。
    # 开始任务
    idx = kwargs.get("task_id")
    logger.info(f"[AI唇动合成] {idx} 新任务")
    try:
        task = AllinpayRobotQiniuLog.objects.get(id=idx, status=0)
    except BaseException as err:
        logger.warn(f"[AI唇动合成] 失败 加载任务失败 {err}")
        return {"rescode": 400, "resmag": "任务异常"}

    # 开始任务
    SDK = syncRequest()
    res = SDK.postLipsync(
        **{
            "audio": task.audio,
            "video": task.video,
        }
    )
    logger.warn(f"[AI唇动合成] {idx} {res}")
    #  {'id': 'ca98f2e1-b26b-4762-85b5-34192637ecee', 'createdAt': '2024-08-28T08:47:15.525188+00:00', 'status': 'PENDING', 'videoUrl': None, 'originalVideoUrl': 'https://oss.3vppt.com/ppt_media/FnTk_d5I0MDY-ydymibvVYIStbmU&video.mp4', 'originalAudioUrl': 'https://oss.3vppt.com/ppt_media/FuqlU-NZqcAvz56L7ojtCVcus82G&output.wav', 'synergize': True, 'creditsDeducted': None, 'webhookUrl': 'https://lease.3vppt.com/rebot/dosync/', 'errorMessage': None}
    if res.get("id"):
        task.description = res.get("id")
        task.save()

    return {"rescode": 200, "resmag": "执行完成"}
